home *** CD-ROM | disk | FTP | other *** search
- /*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/
- /* UList.p */
- /* Copyright © 1984-1990 by Apple Computer Inc. All rights reserved. */
-
- /* Unit UList defines object types TList, a simple dynamic array whose elements are references to
- TObjects, and TSortedList, which maintains the object references in a sequence defined by
- overriding TSortedList.Compare.
- Peter Gaston's scheme for chunky memory allocation has been used by permission.
- Thanks Peter!.
- TList:
- TList is an object which provides a very nice dynamic array of objects.
- It is implemented by appending the dynamic array onto the end of the
- object. Growing and shrinking the array is done by growing and shrinking
- the handle which holds the object.
- TSortedList:
- TSortedList maintains the object references in a sequence defined by
- overriding TSortedList.Compare
- Some Specific uses that TList is especially good for.
- LIFO Stack:
- A push/pop operation is provided.
- FIFO Stack: (Queue)
- Use InsertLast for Queue and First for Dequeue.
- Pre-allocation of your list:
- If you know the size that your list will eventually reach, then you can
- pre-set it to the proper size.
- Delete by Index:
- If you keep track of items by index number, then you can avoid
- a linear search when you want to delete it. Remember though, it
- is a dynamic list and any insertion/deletion activity can cause
- the index to point at a different element than you expect.
- Caveats:
- A _small_ amount of memory is always wasted with this method. An active
- list will generally waste one-half of the chunk size, or
- 4*2=8 bytes/TList.
- */
- #ifndef __UList__
- #define __UList__ 0
- #endif
- #if ! __UList__
- #define __UList__ 1
-
- /* • Auto-Include the requirements for this unit's interface. */
- #ifndef __UObject__
- #include "UObject.h"
- #endif
-
- const short kAllocationIncrement = 6; /* Initial Allocation increment. Six
- elements of slop shouldn't break anybody
- and provides a _nice_ cushion from the
- memory manager. */
- const short kIterateForward = true;
- const short kIterateBackward = ! kIterateForward;
-
- const short kEmptyIndex = 0; /* Value to use when no valid index is
- available Indexes are always positive */
-
- /* Constants for TSortedList.Compare */
- const short kItem1LessThanItem2 = - 1;
- const short kItem1EqualItem2 = 0;
- const short kItem1GreaterThanItem2 = 1;
-
- const short kALessThanB = kItem1LessThanItem2; /* Left in for compatibility (2.0) */
- const short kAEqualB = kItem1EqualItem2; /* Left in for compatibility (2.0) */
- const short kAGreaterThanB = kItem1GreaterThanItem2; /* Left in for compatibility (2.0) */
-
- /* Constants for TSortedList.Search.
- The criteria is considered to be item 2*/
- const short kItemGreaterThanCriteria = kItem1LessThanItem2;
- const short kItemEqualCriteria = kItem1EqualItem2;
- const short kItemLessThanCriteria = kItem1GreaterThanItem2;
-
- typedef struct PtrBasedDoublyLinkedListNode *PtrBasedDoublyLinkedListNodePtr;
- struct PtrBasedDoublyLinkedListNode {
- PtrBasedDoublyLinkedListNodePtr previousLink; /* link to previous node */
- PtrBasedDoublyLinkedListNodePtr nextLink; /* link to next node */
- };
-
- class TPtrBasedDoublyLinkedList : public TObject {
- public:
- /* Manages a doubly linked list of nodes.
- The nodes are pointer based since they
- will typically be on the stack */
- PtrBasedDoublyLinkedListNodePtr fHeadNodePtr; /* HEAD of the linked list */
- PtrBasedDoublyLinkedListNodePtr fTailNodePtr; /* TAIL of the linked list */
- /*Creation/Destruction Methods*/
-
- virtual pascal void IPtrBasedDoublyLinkedList(void);
- /* Initialize a new linked list.*/
-
- virtual pascal void AppendNode(void *thisNode);
- /* Add a new node to the list */
-
- virtual pascal void RemoveNode(void *thisNode);
- /* Remove a node from the list */
-
- virtual pascal void EachNodeDo(pascal void (*DoToNode)(void *thisNode, void *DoToNode_StaticLink
- ), void *DoToNode_StaticLink);
- /* Call do to node for each node in the list, passing a pointer to the node as a
- parameter to the called procedure. */
-
- /* Debugging Methods */
-
- virtual pascal void Fields(pascal void (*DoToField)(StringPtr fieldName, Ptr fieldAddr, short
- fieldType, void *DoToField_StaticLink), void *DoToField_StaticLink);
- /* Used by the Inspector and the Debugger to display the contents of this class's
- fields. */
-
- };
-
- typedef unsigned long ArrayIndex; /* At least always positive ( in this
- universe ) !!! kEmptyIndex..MaxLong
- would be a nice enhancement */
- typedef short CompareResult; /* Negative, zero, and positive results are
- all meaningful even though we have the
- nice constants above. */
-
-
- typedef struct IterationNode *IterationNodePtr;
- struct IterationNode {
- IterationNodePtr previousLink; /* link to previous iteration record */
- IterationNodePtr nextLink; /* link to next iteration record */
- ArrayIndex iterLowBound; /* lower bound of iteration in progress */
- ArrayIndex iterIndex; /* current index of this iteration */
- ArrayIndex iterHighBound; /* upper bound of iteration in progress */
- Boolean iterForward; /* if iteration is forward or backward
- through the list */
- };
-
- class TDynamicArray : public TPtrBasedDoublyLinkedList {
- public: /* TDynamicArrays don't really
- have an IS A relationship
- with
- TPtrBasedDoublyLinkedList but
- have a HAS A relationship
- with it. We subclass it here,
-
- however, because to have a
- HAS A relationship with it
- would require *YET ANOTHER*
- object in the heap and this
- dynamically sized object
- stuff is supposed to help
- reduce that need. */
- ArrayIndex fSize; /* number of elements ACTUALLY in the array,
-
- from 0 to the limit of memory*/
- short fElementSize; /* Size in bytes of an element. MUST be a
- power of 2 ie. 1, 2, 4, 8, 16, etc. */
- short fElementSizeShift; /* the power of 2 for the element size. Will
- be used to avoid DIV and MUL */
-
- ArrayIndex fAllocationIncrement;
- /* Number of elements by which to increase of
- decrease the allocated size of the array
- when it needs to grow or shrink. Thus
- reducing memory manager aggravation. */
- ArrayIndex fAllocatedSize; /* Number of elements for which storage is
- ALLOCATED */
- Boolean fFreeRequested; /* TRUE if the Free method was called but
- couldn't be honored because enumeration
- was in process. Checked at end of
- enumeration and Free is called if true */
- Size fClassSize; /* Used with ComputeAddress to create a
- pointer to an element. This breaks
- encapsulation of GetDynamicArea
- but, is being
- done here for performance reasons (small) */
- /*Creation/Destruction Methods*/
-
- virtual pascal void IDynamicArray(ArrayIndex initialSize, short elementSize);
- /* Initialize a new array with initialSize elements, Always call it once before
- calling any other method. Never call it twice.*/
-
- /* Array manipulation primitives */
-
- virtual pascal ArrayIndex GetSize(void);
- /* Returns the ACTUAL number of elements in the array.*/
-
- virtual pascal void SetArraySize(ArrayIndex theSize);
- /* Sets the array allocation to handle up to theSize elements */
-
- virtual pascal ArrayIndex EachElementDoTil(pascal Boolean (*TestElement)(ArrayIndex elementIndex
- , void *TestElement_StaticLink), void *TestElement_StaticLink, Boolean IterateForward);
-
- /* The basic array iterator. Call TestIndex once for each element of the array, in order,
-
- until TestIndex returns TRUE.
- Return the element that satisfied the test. If none satisfied the tes
- t, return kEmptyIndex.
- */
- virtual pascal void Free(void);
- /* If enumeration of the array is in process, delete all the array elements,
-
- mark the fFreeRequested flag for testing at completion of the enumeration and
- return. Otherwise really free the array. Gee, wouldn't automatic storage
- management be great! */
-
- virtual pascal void InsertElementsBefore(ArrayIndex index, void *ElementPtr, ArrayIndex count);
- /* Insert Elements before the indicated Element. The index of the new element
- will be index. If index = 1 this inserts at the start of the array.
- If index = fSize + 1
- this inserts at the end of the array. Signals Failure if unable to cha
- nge the size of
- the array.
- !!! NOTE MULTIPLE ( >1 ) element moves for non-power of 2 element sizes are NOT
- yet supported! */
-
- virtual pascal void ReplaceElementsAt(ArrayIndex index, void *ElementPtr, ArrayIndex count);
- /* Replaces the Elements at the indicated index.
- !!! NOTE MULTIPLE ( >1 ) element moves for non-power of 2 element sizes are NOT
- yet supported! */
-
- virtual pascal void DeleteElementsAt(ArrayIndex index, ArrayIndex count);
- /* Deletes the Element at the indicated index. Compresses the array
- !!! NOTE MULTIPLE ( >1 ) element moves for non-power of 2 element sizes are NOT
- yet supported! */
-
- virtual pascal void GetElementsAt(ArrayIndex index, void *ElementPtr, ArrayIndex count);
- /* copies count elements to the location specified by ptr.
- !!! NOTE MULTIPLE ( >1 ) element moves for non-power of 2 element sizes are NOT
- yet supported! */
-
- virtual pascal Ptr ComputeAddress(ArrayIndex index);
- /* Returns a pointer to of the index-th element in the array.
- PLEASE NOTE: The return value is a direct heap pointer and should be used with
- care as the heap can compact across calls that move memory; thus invalidating
- the pointer. */
-
- /* Misc. functions */
-
- virtual pascal Boolean IsEmpty(void);
- /* Test if this array is empty or not. */
-
- virtual pascal void Merge(TDynamicArray *aDynamicArray);
- /* merges aDynamicArray with itself. leaves aDynamicArray unchanged.
- !!! NOTE MULTIPLE ( >1 ) element moves for non-power of 2 element sizes are NOT
- yet supported! */
-
- /* Debugging Methods */
-
- virtual pascal void Fields(pascal void (*DoToField)(StringPtr fieldName, Ptr fieldAddr, short
- fieldType, void *DoToField_StaticLink), void *DoToField_StaticLink);
- /* Used by the Inspector and the Debugger to display the contents of this class's
- fields. */
-
- virtual pascal void DynamicFields(pascal void (*DoToField)(StringPtr fieldName, Ptr fieldAddr,
- short fieldType, void *DoToField_StaticLink), void *DoToField_StaticLink);
- /* Used by the Inspector and the Debugger to display the contents of this class's
- dynamic area. */
-
- };
-
- class TList : public TDynamicArray {
- public: /*A dynamic list of TObjects. It IS
- permissible for descendants to add more
- named fields*/
- ObjClassID fObjClassID; /* if <> kNilClass then the Class ID of the
- elements of the list */
- /*Creation/Destruction Methods*/
-
- virtual pascal void IList(void);
- /* Initialize a new list with no elements, i.e., fSize = 0. Always
- call it once before calling any other method. Never call it
- twice.*/
-
- virtual pascal void FreeList(void);
- /* Frees each object in the list, then frees the list.*/
-
- /* Utility Methods*/
-
- virtual pascal TObject *At(ArrayIndex index);
-
- /* Return the index'th element of the list. It is typical for the caller to coerce the
- result into a descendant of TObject. All lists are indexed from 1. Range check only
- if the compile-flag qRangeCheck is TRUE. The static-array equivalent of:
- object := objList.At(index); is: object := objArray[index]; */
-
- virtual pascal ArrayIndex GetEqualItemNo(TObject *item);
-
- /* Return the index of the item in the list, or zero if the item is not in the list. */
-
- virtual pascal ArrayIndex GetSameItemNo(TObject *item);
-
- /* Return the index of the IDENTITY item in the list, or zero if the item is not in the
- list. */
-
- virtual pascal TObject *First(void);
- /* Return the first element of the list. It is typical for the caller to coerce the
- result. Returns NIL if the size is <= 0. */
-
- virtual pascal TObject *Last(void);
- /* Return the last element of the list. It is typical for the caller to coerce the
- result. Returns NIL if the size is <= 0. */
-
- /*Iterator Methods*/
-
- virtual pascal TObject *IterateTil(pascal Boolean (*TestItem)(TObject *item, void *
- TestItem_StaticLink), void *TestItem_StaticLink, Boolean IterateForward, ArrayIndex *itsIndex
- );
-
- /* The basic list iterator. Call TestItem once for each element of the list, in order,
-
- until TestItem returns TRUE.
- Return the element that satisfied the test. If none satisfied the tes
- t, return NIL.
- The actual parameter is typically a procedure whose argument is a desc
- endant of TObject.
- It is typical for the caller to coerce the result into that descendant of TObject.
- If TestItem calls InsertLast, the newly added element will NOT be enumerated.
- If TestItem calls AtPut, InsertBefore, InsertFirst, or DeleteAll, misbehavior will
- ensue. The static-array equivalent of:
- object := objList.FirstThat(Func)
- is:
- object := NIL;
- FOR index := 1 TO fSize DO IF Func(objArray[index]) THEN
- BEGIN
- object := objArray[index];
- LEAVE;
- END;
- */
-
- virtual pascal void Each(pascal void (*DoToItem)(TObject *item, void *DoToItem_StaticLink), void
- *DoToItem_StaticLink);
-
- /* Call DoToItem once for each element of the list, in order. The actual parameter is
- typically a procedure whose argument is a descendant of TObject. If DoToItem calls
- InsertLast, the newly added element will NOT be enumerated. If TestItem calls
- AtPut, InsertBefore, InsertFirst, Delete, or DeleteAll, misbehavior will ensue. If
- DoToItem calls Delete, the item is replaced by the constant kDeletedElement; fSize
- is decremented and fDeletions is incremented. At the end of all calls to Each,
-
- TList.RemoveDeletions will be called. The static-array equivalent of:
- objList.Each(Proc) is:
- FOR index := 1 TO fSize DO
- Proc(objArray[index]);
- */
-
- virtual pascal TObject *FirstThat(pascal Boolean (*TestItem)(TObject *item, void *
- TestItem_StaticLink), void *TestItem_StaticLink);
- /* Call TestItem once for each element of the list, in order, until TestItem returns
- TRUE. Return the element that satisfied the test. If none satisfied the test,
-
- return NIL. The actual parameter is typically a procedure whose argument is a
- descendant of TObject. It is typical for the caller to coerce the result into that
- descendant of TObject. If TestItem calls InsertLast, the newly added element will
- NOT be enumerated. If TestItem calls AtPut, InsertBefore, InsertFirst, Delete, or
- DeleteAll, misbehavior will ensue. */
-
- virtual pascal TObject *LastThat(pascal Boolean (*TestItem)(TObject *item, void *
- TestItem_StaticLink), void *TestItem_StaticLink);
-
- /* Call TestItem once for each element of the list, starting with the last item in the
- list and working toward the first item, until TestItem returns TRUE. Return the
- element that satisfied the test. If none satisfied the test, return NIL. The actual
- parameter is typically a procedure whose argument is a descendant of TObject. It is
- typical for the caller to coerce the result into that descendant of TObject. If
- TestItem calls InsertLast, the newly added element will NOT be enumerated. If
- TestItem calls AtPut, InsertBefore, InsertFirst, Delete, or DeleteAll, misbehavior
- will ensue. */
-
- /*Item Insertion Methods*/
-
- virtual pascal void AtPut(ArrayIndex index, TObject *newItem);
- /* Replace the index'th item of the list. Does not free the old item. If you do this
- from within an Each the results will be unpredictable.*/
-
- virtual pascal void Insert(TObject *item);
- /* Inserts the given item into the list in arrival sequence. */
-
- virtual pascal void InsertBefore(ArrayIndex index, TObject *item);
- /* Insert a reference to an item before the indicated item. The index of the new
- element will be index. If index = 1 this inserts at the start of the list. If index
- = fSize + 1 this inserts at the end of the list. Signals Failure if unable to
- increase the size of the list.*/
-
- virtual pascal void InsertFirst(TObject *item);
-
- /* Insert a reference to item at the front of the list. If the compile-flag qDebug is
- TRUE & SetEltType was called, verify item's type. Increase fSize by 1. The index of
- the new element will be 1. Signals Failure if unable to increase the size of the
- list.*/
-
- virtual pascal void InsertLast(TObject *item);
- /* Insert a reference to item at the back of the list. If the compile-flag qDebug is
- TRUE & SetEltType was called, verify item's type. Increase fSize by 1. The index of
- the new element will be fSize. Signals Failure if unable to increase the size of
- the list.*/
-
- /*Item Deletion Methods*/
-
- virtual pascal void AtDelete(ArrayIndex index);
- /* Deletes via an index (rather than having to search for an item) */
-
- virtual pascal void Delete(TObject *item);
- /* Delete the first reference to item from the list, but do not free item. If item
- does not occur, do nothing. If item does occur, reduce fSize by 1.
- !!! NOTE: This name conflicts with the Pascal builtin: DELETE and we will be
- changing it's name, but changing the name at the _last minute_ isn't a good idea.
- If you need to use the builtin DELETE in a TList subclass, then you will have to
- create a wrapper procedure that forwards to it, for now. Sorry… the Management. */
-
- virtual pascal void DeleteAll(void);
-
- /* Delete every element from the list, but do not free any objects. Leave fSize at 0.*/
-
- virtual pascal void FreeAll(void);
- /* Frees each element in the list. Leave fSize at 0.*/
-
- /* Misc. functions */
-
- virtual pascal void SortBy(pascal CompareResult (*CompareItems)(TObject *item1, TObject *item2,
- void *CompareItems_StaticLink), void *CompareItems_StaticLink);
- /* Sorts the list using the supplied CompareItems function. Uses Shell sort (see
- Sedgewick, "Algorithms", pp. 97-9) */
-
- virtual pascal void Push(TObject *item);
- /* LIFO stack push.(same as insertLast) */
-
- virtual pascal TObject *Pop(void);
- /* LIFO stack pop. */
-
- /* Debugging Methods */
-
- virtual pascal void SetEltType(StringPtr toClass);
- /* Call this once and pass the className of objects you intend to insert into the
- list. The TList insert methods will do a coercion to he type you specify, to ensure
- that the list contains only elements of the right type.*/
-
- virtual pascal void SetEltTypeID(ObjClassID toClassID);
- /* Call this once and pass the ObjClassID of objects you intend to insert into the
- list. The TList insert methods will do a coercion to the type you specify, to
- ensure that the list contains only elements of the right type.*/
-
- virtual pascal void Fields(pascal void (*DoToField)(StringPtr fieldName, Ptr fieldAddr, short
- fieldType, void *DoToField_StaticLink), void *DoToField_StaticLink);
- /* Used by the Inspector and the Debugger to display the contents of this class's
- fields. */
-
- virtual pascal void DynamicFields(pascal void (*DoToField)(StringPtr fieldName, Ptr fieldAddr,
- short fieldType, void *DoToField_StaticLink), void *DoToField_StaticLink);
- /* Used by the Inspector and the Debugger to display the contents of this class's
- dynamic area. */
- virtual pascal void GetInspectorName(StringPtr inspectorName);
- /* Used by the Inspector to display the name of this class. */
-
- };
-
- class TSortedList : public TList {
- public: /* A sorted list of TObjects. Items are
- sorted based on the results of Compare
- which has to be overridden to provide a
- comparison mechanism. */
- virtual pascal void ISortedList(void);
- /* Initialize a sorted list */
-
- virtual pascal TObject *DoSearch(pascal CompareResult (*TestItem)(TObject *anItem, void *
- TestItem_StaticLink), void *TestItem_StaticLink, ArrayIndex *index);
- /* Searches the sorted list until TestItem returns zero or there are no more
- items to search. A binary search is used. */
-
- virtual pascal ArrayIndex GetEqualItemNo(TObject *item);
- /* Return the index of any item that is considered to be equal to the parameter
- 'item'. Two items are considered equal if comparing them with the Compare method
- returns zero. You may wish to use the constants kItemGreaterThanCriteria,
-
- kItemEqualCriteria, kItemLessThanCriteria. */
-
- virtual pascal void Insert(TObject *item);
- /* Inserts the given item into the list in sorted order, using the Compare
- method to determine the item's location relative to other items in the list. */
-
- virtual pascal CompareResult Compare(TObject *item1, TObject *item2);
-
- /* This method compares two items in the list. A negative result indicates that item1
- < item2. A result of zero indicates that item1 = item2. A positive result indicates
- that item1 > item2. You may wish to use the constants kItem1LessThanItem2,
-
- kItem1EqualItem2, kItem1GreaterThanItem2. By default just compare the ordinal value
- of the items. Subclasses that want to should override this method to do any other
- kind of comparison (comparing instance variables, for instance (get it?)). */
-
- virtual pascal TObject *Search(pascal CompareResult (*TestItem)(TObject *anItem, void *
- TestItem_StaticLink), void *TestItem_StaticLink);
- /* This method searches the list of an item that causes your supplied TestItem
- function to return true. This is useful for cases in which you are not comparing
- objects in the list with another object, as does Compare. For example, suppose each
- object has an fTitle field and the objects are inserted into the list in order of
- fTitle. You can use the search method to look for an object whose fTitle is equal
- to any string. A negative TestItem result indicates that your search criteria <
- anItem, a result of zero indicates the item has been found and Search returns that
- item. A positive TestItem result indicates that your search criteria > your anItem.
- */
-
- virtual pascal void Sort(void);
- /* Sorts the list using TSortedList.Compare function and TList.SortBy.*/
-
- virtual pascal void Fields(pascal void (*DoToField)(StringPtr fieldName, Ptr fieldAddr, short
- fieldType, void *DoToField_StaticLink), void *DoToField_StaticLink);
- /* Used by the Inspector and the Debugger to display the contents of this class's
- fields. */
-
- };
-
- extern pascal TList *NewList(void);
- /* A convenience function. Create a TList, initialize it, and return a reference to it.
- Signals Failure if it cannot allocate the object.*/
-
- extern pascal TSortedList *NewSortedList(void);
- /* A convenience function. Create a TSortedList, initialize it, and return a reference t
- o it.
- Signals Failure if it cannot allocate the object.*/
-
- extern pascal TList *NewAllocatedList(ArrayIndex iSize);
- /* A convenience function. The same as NewList, but the initial allocation size can be s
- et. */
-
- extern pascal TList *FreeListIfObject(TList *list);
- /* A convenience function. if list is non-nil then the same as list.FreeList.
- Returns NIL for convenient assignment back to the reference passed in. */
-
- #endif
-
-